package com.apes.fn.scm.internal.help.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.apes.fn.crm.customerExpand.FnCustomerExpand;
import com.apes.fn.scm.internal.help.model.InternalHelpReturnApproval;
import com.apes.fn.scm.internal.help.repository.InternalHelpReturnApprovalRepository;
import com.apes.framework.api.DomainService;
import com.apes.framework.api.SpringManager;
import com.apes.framework.jpa.spec.JpaDsl;
import com.apes.framework.plugin.esb.api.SimpleRequest;
import com.apes.framework.plugin.event.Listener;
import com.apes.framework.plugin.soe.store.database.repository.SceneRepository;
import com.apes.framework.util.LogicalUtil;
import com.apes.framework.util.MapUtil;
import com.apes.scm.account.account.model.InventoryBatch;
import com.apes.scm.account.account.model.Stock;
import com.apes.scm.account.account.repository.InventoryBatchRepository;
import com.apes.scm.account.account.repository.StockRepository;
import com.apes.scm.account.account.service.InventoryService;
import com.apes.scm.account.account.service.ProductAccountService;
import com.apes.scm.masterdata.frame.model.Store;
import com.apes.scm.masterdata.frame.repository.StoreRepository;
import com.apes.scm.masterdata.product.model.Product;
import com.apes.scm.masterdata.product.repository.ProductRepository;
import com.apes.scm.masterdata.stock.model.Depot;
import com.apes.scm.masterdata.stock.model.Location;
import com.apes.scm.masterdata.stock.repository.LocationRepository;
import com.apes.scm.rbac.model.Post;
import com.apes.scm.rbac.model.User;
import com.apes.scm.rbac.repository.PostRepository;
import com.apes.scm.rbac.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @BelongsProject: apes
 * @BelongsPackage: com.apes.fn.scm.internalReturn
 * @ClassName: InternalHelpReturnApprovalService
 * @Author: pyb
 * @CreateTime: 2020-06-02 17:13
 * @Description: 退货申请服务
 * @Version: 1.0
 */
@Service("internalHelpReturnApprovalService")
public class InternalHelpReturnApprovalService extends DomainService {

    @Autowired
    private InternalHelpReturnApprovalRepository internalHelpReturnApprovalRepository;
    @Autowired
    private StockRepository stockRepository;
    @Autowired
    private InventoryBatchRepository inventoryBatchRepository;
    @Autowired
    private ProductRepository productRepository;
    @Autowired
    private LocationRepository locationRepository;
    @Autowired
    private ProductAccountService productAccountService;
    @Autowired
    private InventoryService inventoryService;


    private void test(SimpleRequest simpleRequest){
        String id = simpleRequest.get("id");
        InternalHelpReturnApproval internalHelpReturnApproval = internalHelpReturnApprovalRepository.findOne(id);
        internalHelpReturnApproval.setState("receipt");
        internalHelpReturnApprovalRepository.saveAndFlush(internalHelpReturnApproval);
    }

    /**
     * 保存接口
     *
     * @param request
     * @return
     */
    private InternalHelpReturnApproval save(SimpleRequest request) {
        InternalHelpReturnApproval internalHelpReturnApproval = checkData(request);
        internalHelpReturnApproval.setState("sent");
        internalHelpReturnApproval.setCrossSystem("unidentified");
        internalHelpReturnApproval.setOrderCompany(internalHelpReturnApproval.getReceiptLocation().getCompany());

        if (internalHelpReturnApproval.getScene() == null) {
            internalHelpReturnApproval.setScene(SpringManager.getBean(SceneRepository.class).findOne("SR004")); //注入场景
        }

        internalHelpReturnApproval = internalHelpReturnApprovalRepository.saveAndFlush(internalHelpReturnApproval);
        //更新库存 批次
        updateProductAvailableAndBatch(internalHelpReturnApproval, false, "內协退货保存");
        return internalHelpReturnApproval;
    }

    /**
     * 修改接口
     *
     * @param request
     * @return
     */
    private InternalHelpReturnApproval update(SimpleRequest request) {
        InternalHelpReturnApproval validOrder = getValidOrder(request);
        // 还原商品可用数，减少商品批次冻结数量
        updateProductAvailableAndBatch(validOrder, true, "內协退货编辑");

        InternalHelpReturnApproval internalHelpReturnApproval = checkData(request);
        internalHelpReturnApproval.setState("sent");
        internalHelpReturnApproval = internalHelpReturnApprovalRepository.saveAndFlush(internalHelpReturnApproval);
        //下库存 批次
        updateProductAvailableAndBatch(internalHelpReturnApproval, false, "內协退货编辑");

        return internalHelpReturnApproval;
    }

    /**
     * 申请接口
     *
     * @param request
     * @return
     */
    private InternalHelpReturnApproval apply(SimpleRequest request) {
        InternalHelpReturnApproval approval = request.getO(InternalHelpReturnApproval.class);
        if (approval.getShipLocation().getId().equals(approval.getReceiptLocation().getId())) {
            throw new RuntimeException("同仓库不能做內协退货");
        }
        approval = internalHelpReturnApprovalRepository.findOne(approval.getId());
        approval.setApplyUid(this.getPerson(request));
        approval.setDateApply(new Date());
        approval.setState("apply");


        Depot receiptDepot = approval.getReceiptLocation().getDepot();
        Optional.ofNullable(receiptDepot.getDept())
                .orElseThrow( () -> new RuntimeException("收获仓库的逻辑仓库没有配置部门信息，逻辑仓库：" + receiptDepot.getId()) );

        //获取收货基地所有岗位
        List<Post> posts = SpringManager.getBean(PostRepository.class).findAll(JpaDsl.toCriteriaByEq(
                "branch.id", receiptDepot.getDept().getBranch().getId(), "company.id", approval.getReceiptLocation().getCompany().getId()));
        List<Post> postList = posts.stream()
                .filter(post ->Objects.nonNull(post.getWorkPost()) && LogicalUtil.in(post.getWorkPost().getId(), "0000010", "0000016"))
                .collect(Collectors.toList());
        List<User> userList = new ArrayList<>();
        postList.forEach(post -> {
            List<User> users = SpringManager.getBean(UserRepository.class).findByPost(post.getId());
            userList.addAll(users);
        });
        JSONArray array = userList.stream().distinct().map(User::getId).collect(Collectors.toCollection(JSONArray::new));
        approval.setCandidates(JSON.toJSONString(array));
        return internalHelpReturnApprovalRepository.saveAndFlush(approval);
    }

    /**
     * 基地审核接口
     *
     * @param request
     * @return
     */
    private InternalHelpReturnApproval approve(SimpleRequest request) {
        InternalHelpReturnApproval approval = getValidOrder(request);
        approval = internalHelpReturnApprovalRepository.findOne(approval.getId());
        approval.setApproveUid(this.getPerson(request));
        approval.setDateApprove(new Date());
        approval.setState("approve");
        InternalHelpReturnApproval internalHelpReturnApproval = internalHelpReturnApprovalRepository.saveAndFlush(approval);
        //检查是否需要发货
        checkShip(internalHelpReturnApproval);
        if ("ship".equals(internalHelpReturnApproval.getState())) {
            return internalHelpReturnApprovalRepository.saveAndFlush(internalHelpReturnApproval);
        }
        return approval;
    }

    /**
     * 基地审核驳回接口
     *
     * @param request
     * @return
     */
    private InternalHelpReturnApproval reject(SimpleRequest request) {
        InternalHelpReturnApproval approval = getValidOrder(request);
        approval = internalHelpReturnApprovalRepository.findOne(approval.getId());
        // 还原商品可用数，减少商品批次冻结数量
        updateProductAvailableAndBatch(approval, true, "內协退货审核驳回");
        approval.setApproveUid(this.getPerson(request));
        approval.setDateApprove(new Date());
        approval.setState("reject");
        return internalHelpReturnApprovalRepository.saveAndFlush(approval);
    }

    /**
     * 删除接口
     *
     * @param request
     * @return
     */
    private String delete(SimpleRequest request) {
        InternalHelpReturnApproval approval = request.getO(InternalHelpReturnApproval.class);
        internalHelpReturnApprovalRepository.delete(approval.getId());
        // 还原商品可用数，减少商品批次冻结数量
        updateProductAvailableAndBatch(approval, true, "內协退货单删除");
        return "删除成功";
    }

    /**
     * 检查数据
     *
     * @param request
     * @return
     */
    private InternalHelpReturnApproval checkData(SimpleRequest request) {
        InternalHelpReturnApproval approval = request.getO(InternalHelpReturnApproval.class);
        if (approval.getShipLocation().getId().equals(approval.getReceiptLocation().getId())) {
            throw new RuntimeException("同仓库不能做內协退货");
        }
        JSONObject tempJson = request.getJO();
        FnCustomerExpand customerExpand = this.invoke("fn.customerExpand.updateOrInsert", MapUtil.mapper(
                "customerExpand", tempJson.get("customerExpand"),
                "customer", tempJson.get("customer"),
                "customerCar", tempJson.get("customerCar")
        ));
        approval.setCustomerExpand(customerExpand);
        //重新计算税金  总价
        approval.computeAmt();
        return approval;
    }

    /**
     * 功能：判断是否需要发货
     * 无需发货直接设置单据为已发货状态
     */
    public void checkShip(InternalHelpReturnApproval approval) {
        long result = approval.getApprovalItems().stream()
                .filter(orderItem -> LogicalUtil.in(orderItem.getProduct().getType(), "aut"))
                .count();
        if (result == approval.getApprovalItems().size()) {
            if (!"approve".equals(approval.getState())) return;
            approval.setState("ship");
            approval.setCrossSystem("unidentified");
        }
    }

    /**
     * 获取有效订单
     *
     * @param request
     * @return
     */
    private InternalHelpReturnApproval getValidOrder(SimpleRequest request) {
        InternalHelpReturnApproval internalHelpReturnApproval = internalHelpReturnApprovalRepository.findOne((String) request.get("id"));
        Optional.ofNullable(internalHelpReturnApproval).orElseThrow(() -> new RuntimeException("內协退货订单：" + request.get("id") + " 在系统中不存在!"));
        if ((int) request.get("version") != internalHelpReturnApproval.getVersion())
            throw new RuntimeException("內协退货订单已发生改变,请重新查询內协退货订单状态！");
        return internalHelpReturnApproval;
    }

    /**
     * 查询所有基地下的仓库
     *
     * @param request
     * @return
     */
    public Page<Location> findByBase(SimpleRequest request) {
        //获取所有基地
        List<Store> stores = SpringManager.getBean(StoreRepository.class).findAll(JpaDsl.toCriteriaByEq("storeType.code", "20"));
        if (stores.size() == 0) {
           throw  new RuntimeException("未找到任何基地");
        }
        List<String> deptIds = stores.stream().map(Store::getId).collect(Collectors.toList());
        if (!request.getMap().containsKey("key")) {
            List<Map> filters = request.get("condition");

            Map mp = new HashMap();
            mp.put("field", "depot.dept.id");
            mp.put("operator", "IN");
            mp.put("value", deptIds);
            filters.add(mp);
            return locationRepository.findAll(JpaDsl.toCriteria(filters), PageRequest.of(request.get("page"), request.get("size")));
        }
        String value = request.get("key");
        return locationRepository.findByBase(value, value,
                deptIds, PageRequest.of(request.get("page"), request.get("size")));
    }


    /**
     * 查找可退商品批次(含【A00000】期初供应商)
     *
     * @param request
     * @return Page<InventoryBatch>
     */
    public Page<InventoryBatch> findInventory(SimpleRequest request) {
        JSONObject requestJO = request.getJO();
        String productId = requestJO.getString("productId");
        String locationId = requestJO.getString("locationId");
        String companyId = requestJO.getString("companyId");

        //批次上的供应商为该退货基地
        String receiptLocationId = requestJO.getString("receiptLocation");
        Location location = locationRepository.findOne(receiptLocationId);

        String supplierId = location.getCompany().getParty().getPatyRoleByType("Supplier").getId();

        //判断工时商品
        Product product = productRepository.findOne(productId);
        //工时商品无库存 无法填可用数 暂定99
        double usableQty = 99;

        if (LogicalUtil.notIn(product.getType(), "aut")) {
            // 查找商品库存帐的可用数是否大于0
            Stock stock = stockRepository.findFirstByProductIdAndLocationIdAndUsableQtyGreaterThan(productId, locationId, 0);
            // 获取可用数
            usableQty = Optional.ofNullable(stock).map(Stock::getUsableQty).orElseThrow(() -> new RuntimeException("商品库存帐不满足退货条件！"));
        }

        // 获取结存大于冻结的批次
        Page<InventoryBatch> inventoryBatchPage = inventoryBatchRepository.findReturnableByCompanyIdAndProductIdAndSupplier(companyId, productId, supplierId, PageRequest.of(request.get("page"), request.get("size")));
        //lambda 表达式中使用的变量应为 final 或 effectively final 复制usableQty到临时变量
        double finalUsableQty = usableQty;
        inventoryBatchPage.getContent().forEach(
                (inventoryBatch) -> {
                    inventoryBatch.setUsableQty(finalUsableQty);
                    inventoryBatch.setCanReturnQty(Math.min(finalUsableQty, inventoryBatch.getBalanceQty() - inventoryBatch.getFrostQty()));
                }
        );
        return inventoryBatchPage;
    }

    /**
     * 更新商品库存可用数，批次表冻结数量
     *
     * @param internalHelpReturnApproval
     * @param flag
     * @param note
     */
    private void updateProductAvailableAndBatch(InternalHelpReturnApproval internalHelpReturnApproval, boolean flag, String note) {
        internalHelpReturnApproval.getApprovalItems().forEach(item -> {
            //退货数量
            double changeQty = Math.abs(item.getProductReturnQty());
            if (!flag) {
                changeQty = -1 * changeQty;
            }
            if (LogicalUtil.notIn(item.getProduct().getType(), "aut")) {
                // 减少（增加）商品可用数
                productAccountService.setProductAvailable(item.getProduct(), internalHelpReturnApproval.getShipLocation(),
                        item.getUom(), changeQty, internalHelpReturnApproval.getInnerBusinessType(), internalHelpReturnApproval.getId(),
                        String.valueOf(item.getId()), note, internalHelpReturnApproval.getCompany());
            }
            // 增加（减少）商品价值（商品批次） 的冻结数量
            // 查询批次信息
            InventoryBatch inventoryBatch = inventoryBatchRepository.findOne(item.getInventoryBatch().getId());
            //  增加（减少）冻结数量
            inventoryService.changeFrostQty(inventoryBatch, item.getUom(),-1 * changeQty,internalHelpReturnApproval.getReceiptLocation().getCompany(),
                    internalHelpReturnApproval.getInnerBusinessType(),internalHelpReturnApproval.getId(),item.getId(),note);
        });
    }

    /**
     * erp系统收货后回写(第一版暂不考虑物流损坏和部分拒收业务，默认一次性全部收货)
     *
     * @param request
     * @return
     */
    private InternalHelpReturnApproval internalHelpReturnReceipt(SimpleRequest request) {
        JSONObject requestJO = request.getJO();
        if (!"InternalHelpReturn".equals(requestJO.getString("sourceType"))) {
            throw new RuntimeException(String.format("推送收货事件异常！单据[%s][%s]不是赋能门店內协退货单据", requestJO.getString("source"), requestJO.getString("sourceType")));
        }
        //查找內协退货审批单
        InternalHelpReturnApproval returnApproval = internalHelpReturnApprovalRepository.findOne(requestJO.getString("source"));
        Optional.ofNullable(returnApproval).orElseThrow(() -> new RuntimeException(String.format("未找到內协退货审批单[%s]！单据已被删除或失效，请检查！", requestJO.getString("source"))));
        //将单据状态更改为已收货
        returnApproval.setState("receipt");
        return internalHelpReturnApprovalRepository.saveAndFlush(returnApproval);
    }

    /**
     * 功能：处理交货完成事件
     */
    @Listener(topic = "event:stock.pick.delivery")
    public void delivery(SimpleRequest request) {
        JSONObject param = request.getJO();
        if (!param.getString("originBusinessType").equals(InternalHelpReturnApproval.class.getSimpleName())) return;

        InternalHelpReturnApproval internalHelpReturnApproval = internalHelpReturnApprovalRepository.findOne(param.getString("origin"));
        if ("deliver".equals(param.getString("operation"))) {
            // 更新交货状态以及单据状态
            internalHelpReturnApproval.setState("ship");
            internalHelpReturnApproval.setCrossSystem("unidentified");
            // 用于判断是否触发场景流
            if ("ship".equals(internalHelpReturnApproval.getState()))
                internalHelpReturnApprovalRepository.saveAndFlush(internalHelpReturnApproval);
        } else {
            // 更新交货状态以及单据状态
            internalHelpReturnApproval.setState("receipt");
            internalHelpReturnApproval.setCrossSystem("esb");
            // 用于判断是否触发场景流
            if ("receipt".equals(internalHelpReturnApproval.getState()))
                internalHelpReturnApprovalRepository.saveAndFlush(internalHelpReturnApproval);
        }
    }


    /**
     * fnInnerPickDeliveryUpCar.query
     * 内协退货查询条件转换
     * @param request
     * @return customAction="true"
     * @throws Exception
     */
    public com.apestech.framework.json.JSONObject internalHelpReturnQuery(SimpleRequest request) throws Exception {
        JSONObject jo = request.getJO();
        JSONArray condition = jo.getJSONArray("condition");
        if (condition != null) {
            for (int i = 0; i < condition.size(); i++) {
                if ("DONE_DATE".equals(condition.getJSONObject(i).getString("field"))){
                    JSONObject json = new JSONObject();
                    if("GTE".equals(condition.getJSONObject(i).getString("operator"))){
                        json.put("field","DONE_DATE_START");
                        json.put("operator","EQ");
                        json.put("value",condition.getJSONObject(i).getString("value"));
                        json.put("type","date");
                        condition.add(json);
                    }else if("LTE".equals(condition.getJSONObject(i).getString("operator"))){
                        json.put("field","DONE_DATE_END");
                        json.put("operator","EQ");
                        json.put("value",condition.getJSONObject(i).getString("value"));
                        json.put("type","date");
                        condition.add(json);
                    }
                }
                if ("RETURN_CREATE_DATE".equals(condition.getJSONObject(i).getString("field"))){
                    JSONObject json = new JSONObject();
                    if("GTE".equals(condition.getJSONObject(i).getString("operator"))){
                        json.put("field","RETURN_CREATE_DATE_START");
                        json.put("operator","EQ");
                        json.put("value",condition.getJSONObject(i).getString("value"));
                        json.put("type","date");
                        condition.add(json);
                    }else if("LTE".equals(condition.getJSONObject(i).getString("operator"))){
                        json.put("field","RETURN_CREATE_DATE_END");
                        json.put("operator","EQ");
                        json.put("value",condition.getJSONObject(i).getString("value"));
                        json.put("type","date");
                        condition.add(json);
                    }
                }
            }
            jo.put("condition", condition);
        }
        return com.apestech.framework.json.JSON.toJSON(jo.toJSONString());
    }


}
